
#ifndef  LOGIMPL_H
#define  LOGIMPL_H

#include <memory>
#include "recovery/Status.h"
#include "ILog.h"

class Topic;
namespace recovery {
namespace fs {
namespace file {
    class FileLogOperation;
}
}
}

/*  
class ILogHeader {
public:
    virtual ~LogHeader() {}

    virtual size_t size() const = 0;
    virtual const uint8_t * data() const = 0;

    virtual void setBodySize(size_t bodySize)  = 0;
    virtual size_t bodySize() const = 0;
    virtual void incBodySize(size_t incSize) = 0;

    virtual bool isFileSizeValid(size_t fileSize) = 0;

    virtual void reset() = 0;
    virtual std::string toString() const  = 0;
};

*/
class LogImpl : public ILog{
public:
	class Meta  : public IMeta {
	public:
        Meta(LogImpl & logImpl);
        ~Meta() override;

		size_t offset() const ;
		Meta & setOffset(size_t offset);
		Meta & addOffset(size_t offset);

		recovery::Status sync() override;

        class LogImplSize : public ILogSize {
        public:	
            LogImplSize(LogImpl & logImpl):ILogSize(0), _logImpl(logImpl) {}
            ~LogImplSize() override {}

            size_t value() const override { 
                size_t sz = 0;
                _logImpl.size(sz);
                return sz;
            }
            recovery::Status advance(size_t delta) override { 
                _logImpl._header.incBodySize(delta);
                return _logImpl.writeLogHeader(_logImpl._header);
            } 
            recovery::Status overwrite(size_t fileSize) override { 
                _logImpl.saveLogHeader(fileSize);
                return _logImpl.writeLogHeader(_logImpl._header);
            }
        private:
            LogImpl & _logImpl;
        };
        ILogSize & logSize() const override {
            return *_logSize;
        }

        size_t size() const override{ return _logImpl._header.size(); };

        recovery::Status load() override {
            //TODO:
            return recovery::Status::OK();
        }

    private:
        LogImpl & _logImpl;
        friend class LogImpl;

        ILogSize * _logSize;
	};


	LogImpl(Topic & topic);
	~LogImpl() override ;

	Meta & meta(){ return _meta; }

	recovery::Status open() override;
	recovery::Status close() override;

	recovery::Status append(const std::string & data, size_t & appendedBytes) override;
	recovery::Status sync() override;
	recovery::Status truncate(size_t size) override;
    recovery::Status size(size_t & sz) const override;


    class LogHeader {
    public:
        LogHeader() {}
        ~LogHeader() {}

        static constexpr size_t HeaderSize() { return sizeof(size_t); }

        size_t size() const { return LogHeader::HeaderSize();}
        const uint8_t * data() const { return reinterpret_cast<const uint8_t*>(&_bodySize); }


        void setBodySize(size_t bodySize) { this->_bodySize = bodySize; }
        size_t bodySize() const { return this->_bodySize; }
        void incBodySize(size_t incSize) { this->_bodySize += incSize; }

        void reset(){ 
            _bodySize = 0; 
        }

        bool isValid(size_t fileSize){
            return (size() + _bodySize) == fileSize;
        }

        std::string toString() const ;
    private:
        size_t _bodySize = 0;
        //TODO:  size_t _next_trans_id = 0;
    };

    recovery::Status readLogHeader(LogHeader & header) const;
    recovery::Status writeLogHeader(const LogHeader & header) const ;


    void saveLogHeader(size_t offset) {
        if(offset >= LogHeader::HeaderSize())
            _header.setBodySize(offset - LogHeader::HeaderSize());
        else{
            //TODO:
        }
    }

private:
	Topic & _topic;
	Meta _meta;
    LogHeader _header;
    std::unique_ptr<recovery::fs::file::FileLogOperation> _log;
};

#endif   /* LOGIMPL_H */
